﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Plugins;
using Plugins.UserControls;
using SMAPlugin.Common;
using StockModel;
using Utils;

namespace SMAPluginIntegrationTests
{
	[TestClass]
	public class DecisionEngineITs
	{
		#region Attributes

		private List<Operation> _operations;

		private StockParametersSelectorData _stockParameters;
		private StrategyControlData _pluginSettings;
		private HourSelectorData _hourSettings;
		private FakeOrderExecutor _orderExecutor;
		private OperationManager _operationManager;
		private ObservableCollection2<Quotation> _source;
		private DecisionEngineData _data;
		private DecisionEngine _decisionEngine;

		#endregion

		#region Test Setup

		[TestInitialize]
		public void Initialize()
		{
			_operations = new List<Operation>();
		}

		#endregion

		#region Test Methods

		[TestMethod]
		public void TestDecisionEngineLastFastCrossSingle()
		{
			this.TestDecisionEngineLastFastCrossInitialize();
			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("17/12/2012 9:00:00"));
			this.TestDecisionEngineLastFastCrossClean();
		}

		[TestMethod]
		public void TestDecisionEngineLastFastCrossRepeated()
		{
			this.TestDecisionEngineLastFastCrossInitialize();

			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("17/12/2012 9:00:00"));

			this.CloseDay(DateTime.Parse("17/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("17/12/2012 9:00:00"));

			this.TestDecisionEngineLastFastCrossClean();
		}

		[TestMethod]
		public void TestDecisionEngineLastFastCrossMultiple()
		{
			this.TestDecisionEngineLastFastCrossInitialize();

			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("17/12/2012 9:00:00"));

			// This has to be done manually but the engine will detect the last quotation and set it after forced closeing time
			this.CloseDay(DateTime.Parse("17/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("18/12/2012 9:00:00"));
			this.CloseDay(DateTime.Parse("18/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineLastFastCrossInternal(DateTime.Parse("19/12/2012 9:00:00"));
			this.CloseDay(DateTime.Parse("19/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineLastFastCrossClean();
		}

		[TestMethod]
		public void TestDecisionEngineSlowFastCrossFixedWinSingle()
		{
			this.TestDecisionEngineSlowFastCrossFixedWinInitialize();
			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("17/12/2012 9:00:00"));
			this.TestDecisionEngineSlowFastCrossFixedWinClean();
		}

		[TestMethod]
		public void TestDecisionEngineSlowFastCrossFixedWinRepeated()
		{
			this.TestDecisionEngineSlowFastCrossFixedWinInitialize();

			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("17/12/2012 9:00:00"));

			this.CloseDay(DateTime.Parse("17/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("17/12/2012 9:00:00"));

			this.TestDecisionEngineSlowFastCrossFixedWinClean();
		}

		[TestMethod]
		public void TestDecisionEngineSlowFastCrossFixedWinMultiple()
		{
			this.TestDecisionEngineSlowFastCrossFixedWinInitialize();

			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("17/12/2012 9:00:00"));

			// This has to be done manually but the engine will detect the last quotation and set it after forced closeing time
			this.CloseDay(DateTime.Parse("17/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("18/12/2012 9:00:00"));
			this.CloseDay(DateTime.Parse("18/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime.Parse("19/12/2012 9:00:00"));
			this.CloseDay(DateTime.Parse("19/12/2012 17:31:00"));
			Assert.AreEqual(DecisionEngineState.DayClosed.Name, _data.State.Name);

			this.TestDecisionEngineSlowFastCrossFixedWinClean();
		}

		#endregion

		#region Internal Methods

		private void TestDecisionEngineLastFastCrossInitialize()
		{
			_stockParameters = new StockParametersSelectorData();
			_pluginSettings = new StrategyControlData();
			_hourSettings = new HourSelectorData();

			_pluginSettings.SlowSMAPeriod = 4;
			_pluginSettings.FastSMAPeriod = 2;
			_pluginSettings.WorkingMode = WorkingMode.LastFastCross;

			_hourSettings.StartWithOpening = true;
			_hourSettings.LastOpen = new TimeSpan(17, 0, 0);
			_hourSettings.ForcedCloseTime = new TimeSpan(17, 30, 0);

			_stockParameters.FixedFeePerOperation = 1;
			_stockParameters.FixedReserve = 300;
			_stockParameters.ValueMultiplier = 1;

			_orderExecutor = new FakeOrderExecutor();

			_operationManager = new OperationManager(_stockParameters, _orderExecutor);
			_operationManager.StockSymbol = "Test";
			_source = new ObservableCollection2<Quotation>();
			_data = new DecisionEngineData();
			_decisionEngine = new DecisionEngine(_data, _source, _pluginSettings, _hourSettings, _operationManager);

			_operationManager.OperationExecuted += OperationManager_OperationExecuted;
		}

		private void TestDecisionEngineLastFastCrossInternal(DateTime testDate)
		{
			_orderExecutor.NextQuotation = new Quotation();
			_orderExecutor.NextQuotation.Buyers.Add(new Order(10, 10));
			_orderExecutor.NextQuotation.Sellers.Add(new Order(20, 10));

			_pluginSettings.Volume = 1;

			_source.Add(this.CreateQuotation(1.0m, 0, 2.0m, 3.0m, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(2.0m, 0, 2.0m, 3.0m, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(3.0m, 0, 2.0m, 3.0m, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(3.0m, 1, 2.0m, 3.0m, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4.0m, 1, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(5.0m, 2, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4.0m, 3, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(5.0m, 4, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(6.0m, 5, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4.0m, 6, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
			Assert.AreEqual(1, _operations.Count);
			Assert.AreEqual(20, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(10, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-10, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-12, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_orderExecutor.NextQuotation = new Quotation();
			_orderExecutor.NextQuotation.Buyers.Add(new Order(25, 10));
			_orderExecutor.NextQuotation.Sellers.Add(new Order(35, 10));

			_source.Add(this.CreateQuotation(4.5m, 7, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8.0m, 8, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4.0m, 8, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(10.0m, 8, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(10.0m, 9, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(10.0m, 10, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8.0m, 11, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			Assert.AreEqual(2, _operations.Count);
			Assert.AreEqual(35, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(25, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-10, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-12, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_orderExecutor.NextQuotation = new Quotation();
			_orderExecutor.NextQuotation.Buyers.Add(new Order(10, 10));
			_orderExecutor.NextQuotation.Sellers.Add(new Order(20, 10));

			_source.Add(this.CreateQuotation(9.0m, 12, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(7.0m, 13, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(7.0m, 14, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(7.0m, 15, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(6.8m, 16, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8.0m, 17, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);

			Assert.AreEqual(3, _operations.Count);
			Assert.AreEqual(20, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(10, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-10, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-12, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_orderExecutor.NextQuotation = new Quotation();
			_orderExecutor.NextQuotation.Buyers.Add(new Order(55, 1));
			_orderExecutor.NextQuotation.Sellers.Add(new Order(75, 1));

			_source.Add(this.CreateQuotation(7.0m, 18, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);

			Assert.AreEqual(4, _operations.Count);
			Assert.AreEqual(20, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(55, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(35, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(33, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_pluginSettings.Volume = 10;

			_orderExecutor.NextQuotation = new Quotation();
			_orderExecutor.NextQuotation.Buyers.Add(new Order(55, 1));
			_orderExecutor.NextQuotation.Sellers.Add(new Order(75, 1));

			_source.Add(this.CreateQuotation(17.0m, 19, 2.0m, 3.0m, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
		}

		private void TestDecisionEngineLastFastCrossClean()
		{
			_operationManager.OperationExecuted -= OperationManager_OperationExecuted;
		}

		private void TestDecisionEngineSlowFastCrossFixedWinInitialize()
		{
			_stockParameters = new StockParametersSelectorData();
			_pluginSettings = new StrategyControlData();
			_hourSettings = new HourSelectorData();

			_pluginSettings.SlowSMAPeriod = 4;
			_pluginSettings.FastSMAPeriod = 2;
			_pluginSettings.Volume = 1;
			_pluginSettings.WorkingMode = WorkingMode.FastSlowCrossFixedWin;
			_pluginSettings.FixedWin = 1;

			_hourSettings.StartWithOpening = true;
			_hourSettings.LastOpen = new TimeSpan(17, 0, 0);
			_hourSettings.ForcedCloseTime = new TimeSpan(17, 30, 0);

			_stockParameters.FixedFeePerOperation = 1;
			_stockParameters.FixedReserve = 300;
			_stockParameters.ValueMultiplier = 1;

			_orderExecutor = new FakeOrderExecutor();

			_operationManager = new OperationManager(_stockParameters, _orderExecutor);
			_operationManager.StockSymbol = "Test";
			_source = new ObservableCollection2<Quotation>();
			_data = new DecisionEngineData();
			_decisionEngine = new DecisionEngine(_data, _source, _pluginSettings, _hourSettings, _operationManager);

			_operationManager.OperationExecuted += OperationManager_OperationExecuted;
		}

		public void TestDecisionEngineSlowFastCrossFixedWinInternal(DateTime testDate)
		{
			_pluginSettings.Volume = 1;

			_source.Add(this.CreateQuotation(9.0m, 0, 0, 0, 0, 0, 0, 0, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(9.0m, 0, 0, 0, 0, 0, 0, 0, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(9.0m, 0, 0, 0, 0, 0, 0, 0, 0, 0, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingOpen.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(1, 1, 0, 5, 1, 1, 1, 1, 2, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(2, 2, 1, 2, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(3, 3, 2, 3, 1, 1, 3, 4, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingSlowAverage.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(4, 4, 3, 4, 1, 1, 4, 5, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(5, 5, 4, 5, 1, 1, 5, 6, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(6, 6, 5, 6, 1, 1, 6, 7, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(7, 7, 6, 7, 1, 1, 7, 8, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8, 8, 7, 8, 1, 1, 7, 8, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(7, 9, 7, 8, 1, 1, 6, 7, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(6, 10, 6, 7, 1, 1, 5, 6, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(5, 11, 5, 6, 1, 1, 4, 5, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4, 12, 4, 5, 1, 1, 3, 4, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(3, 13, 3, 4, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);

			// The operation is executed at possition exit
			Assert.AreEqual(1, _operations.Count);
			Assert.AreEqual(3, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(5, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(2, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(0, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_source.Add(this.CreateQuotation(2, 14, 2, 3, 1, 1, 1, 2, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(1, 15, 1, 2, 1, 1, 6, 7, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossUp.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(7, 16, 6, 7, 1, 1, 7, 8, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8, 17, 7, 8, 1, 1, 19, 20, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnLongPossition.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(20, 18, 19, 20, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			// The operation is executed at possition exit
			Assert.AreEqual(2, _operations.Count);
			Assert.AreEqual(8, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(2, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-6, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-8, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_source.Add(this.CreateQuotation(2, 19, 2, 3, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(2, 20, 2, 3, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(3, 21, 2, 3, 1, 1, 3, 4, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(4, 22, 3, 4, 1, 1, 5, 6, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			// The operation is executed at possition exit
			Assert.AreEqual(3, _operations.Count);
			Assert.AreEqual(6, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(2, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-4, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-6, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_source.Add(this.CreateQuotation(6, 23, 5, 6, 1, 1, 7, 8, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(8, 24, 7, 8, 1, 1, 9, 10, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(10, 25, 9, 10, 1, 1, 11, 12, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(12, 26, 11, 12, 1, 1, 2, 3, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(2, 27, 2, 3, 1, 1, 0.5m, 1, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(0.5m, 28, 0.5m, 1, 1, 1, 4, 5, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(5, 29, 4, 5, 1, 1, 6, 7, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(7, 30, 6, 7, 1, 1, 6, 7, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			// The operation is executed at possition exit
			Assert.AreEqual(4, _operations.Count);
			Assert.AreEqual(7, _operations[_operations.Count - 1].BuyPrice);
			Assert.AreEqual(0.5m, _operations[_operations.Count - 1].SellPrice);
			Assert.AreEqual(-6.5m, _operations[_operations.Count - 1].ResultWithoutFees);
			Assert.AreEqual(-8.5m, _operations[_operations.Count - 1].Result);
			Assert.AreEqual(1, _operations[_operations.Count - 1].Volume);

			_source.Add(this.CreateQuotation(6, 31, 6, 7, 1, 1, 5, 6, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.WaitingCrossDown.Name, _data.State.Name);

			_source.Add(this.CreateQuotation(5, 32, 5, 6, 1, 1, 4, 5, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
			_source.Add(this.CreateQuotation(4, 33, 4, 5, 1, 1, 0, 0, 1, 1, testDate));
			Assert.AreEqual(DecisionEngineState.OnShortPossition.Name, _data.State.Name);
		}

		private void OperationManager_OperationExecuted(object sender, OperationExecutedEventArgs e)
		{
			_operations.Add(e.Operation);
		}

		private void TestDecisionEngineSlowFastCrossFixedWinClean()
		{
			_operationManager.OperationExecuted -= OperationManager_OperationExecuted;
		}

		#endregion

		#region Utility Methods

		private void CloseDay(DateTime closingTime)
		{
			Quotation closingQuote = this.CreateQuotation(16.0m, 20, 2.0m, 3.0m, 1, 1, closingTime);
			closingQuote.Date = closingTime;

			_source.Add(closingQuote);
			_source.Clear();
			_operations.Clear();
		}

		private Quotation CreateQuotation(decimal value, int volume, decimal buyValue, decimal sellValue, int buyVolume, int sellVolume, DateTime date)
		{
			date = date.AddMinutes(_source.Count);

			Quotation result = new Quotation() { Value = value, Volume = volume, Date = date };
			result.Buyers.Add(new Order(buyValue, buyVolume));
			result.Sellers.Add(new Order(sellValue, sellVolume));

			return result;
		}

		private Quotation CreateQuotation(decimal value, int volume, decimal buyValue, decimal sellValue, int buyVolume, int sellVolume, decimal nextBuyValue, decimal nextSellValue, int nextBuyVolume, int nextSellVolume, DateTime date)
		{
			Quotation result = new Quotation() { Value = value, Volume = volume, Date = date };
			result.Buyers.Add(new Order(buyValue, buyVolume));
			result.Sellers.Add(new Order(sellValue, sellVolume));

			Quotation nextQuotation = new Quotation();
			nextQuotation.Buyers.Add(new Order(nextBuyValue, nextBuyVolume));
			nextQuotation.Sellers.Add(new Order(nextSellValue, nextSellVolume));

			_orderExecutor.NextQuotation = nextQuotation;

			return result;
		}

		#endregion
	}
}
